package br.biofoco.p2p.dht;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.biofoco.p2p.config.ConfigConstants;
import br.biofoco.p2p.peer.ID;
import br.biofoco.p2p.peer.IDFactory;
import br.biofoco.p2p.peer.PeerConfig;
import br.biofoco.p2p.peer.ProxyPeer;
import br.biofoco.p2p.rpc.EndPoint;
import br.biofoco.p2p.rpc.EndpointFactory;
import br.biofoco.p2p.rpc.Protocol;

import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;

public class SeedProvider {

	private static final Logger LOGGER = LoggerFactory.getLogger(SeedProvider.class);
	private final EndpointFactory endpointFactory;
	private String filename;

	@Inject
	public SeedProvider(EndpointFactory endpointFactory) {
		this.endpointFactory = endpointFactory;
		filename = System.getProperty("config.dir", "conf") + File.separator + ConfigConstants.SEED_FILE;
	}

	public Collection<ProxyPeer> retrieveSeeds()  {
		
		LOGGER.debug("Loading seed list...");

		try {
			
			Collection<ProxyPeer> seeds = parseFile(filename);
			LOGGER.debug("SeedProvider.retrieveSeeds() - See all peer retrieved from seeds.xml: ");
			LOGGER.debug("SeedProvider.retrieveSeeds() - " + seeds.toString());
			return ImmutableList.copyOf(seeds);			
			
		} catch (DocumentException e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage());
			return ImmutableList.of();			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage());
			return ImmutableList.of();	
		}

	}

	private Collection<ProxyPeer> parseFile(String filename) throws FileNotFoundException, DocumentException {

		SAXReader reader = new SAXReader();
		Document doc = reader.read(new FileInputStream(filename));
		Element root = doc.getRootElement();

		List<ProxyPeer> seeds = new ArrayList<ProxyPeer>();

		for (Object s : root.elements("seed")) {

			Element seed = (Element) s;
			Collection<EndPoint> endpoints = createEndpoints(seed.element("endpoints"));

			if (endpoints.size() == 0)
				throw new IllegalArgumentException("seed list cannot be null!");

			for (EndPoint endPoint : endpoints) {
				ID tentativeID = IDFactory.newRandomID();
				PeerConfig config = new PeerConfig();
				config.setPeerID(tentativeID);
				config.add(endPoint);
				ProxyPeer node = new ProxyPeer(config);
				LOGGER.debug("SeedProvider.parseFile() - Adding peer node: " + node.toString());
				seeds.add(node);				
			}
		}

		return seeds;
	}

	private Collection<EndPoint> createEndpoints(Element element) {

		List<EndPoint> endpoints = new ArrayList<EndPoint>();

		for (Object e : element.elements("endpoint")) {

			String rawText = ((Element) e).getText().trim();
			StringTokenizer str = new StringTokenizer(rawText, "://");

			String protocol = str.nextToken();
			String address  = str.nextToken();
			int port = Integer.parseInt(str.nextToken());

			EndPoint ep = endpointFactory.createEndpoint(Protocol.of(protocol), address, port);
			endpoints.add(ep);
		}
 
		LOGGER.debug("Endpoints detected: " + endpoints);

		return endpoints;
	}

}
